package ioc.entry.resources;

import org.apache.commons.beanutils.BeanUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author songyouchao
 * @ClassName DefaultListableBeanFactory.java
 * @Description  基础容器的核心实现 存储对象
 * @createTime 2021年07月27日
 */
public class DefaultListableBeanFactory implements BeanFactory {

    //存储bean的定义  beanName : beanDefinition 主要存放的实例还是在下面这个map中
    private Map<String,BeanDefinition> beanDefinitionMap  = new ConcurrentHashMap();

    //存储对象实例 其实最终的 getBean 是从这里取出的
    private Map<String,Object> singletonObjects = new ConcurrentHashMap<String, Object>();

    /**
     * @Author songyouchao
     * @Description  实现getBean
     * @Date 19:50 2021/7/27
     * @Param [className]
     * @return java.lang.Object
     **/
    public Object getBean(String beanName) {
        if(singletonObjects.containsKey(beanName)){
            return singletonObjects.get(beanName);
        }else{
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if(beanDefinition==null){
                throw new RuntimeException("NoSuchBeanDefinition : 你找的 "+beanName+" 对象 不存在");
            }
            /**
             * 这里有个小点 需要注意 如果是单例 他会将创建好的bean放到单例map中 下次取就直接走的最开始的if 如果多例的话 我认为是 直接去创建bean 不再判断单例map中是不是存在了
             * 这里作为了解 按照单例来处理
             */
            //创建bean
            Object bean = createBean(beanDefinition);
            //放到单例map中
            singletonObjects.put(beanName,bean);
            //return
            return bean;
        }
    }

    /**
    *
     * @Author songyouchao
     * @Description  把bean的定义存放到map中（注册到容器中）
     * @Date 19:54 2021/7/27
     * @Param [beanDefinition]
     * @return void
     **/
    public void registerBeanDefinition(BeanDefinition beanDefinition){
        beanDefinitionMap.put(beanDefinition.getBeanName(),beanDefinition);
    }

    Object createBean(BeanDefinition beanDefinition){
        Class<?> aClass ;
        try{
            aClass = Class.forName(beanDefinition.getClassName());
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("类未找到"+e.getMessage());
        }

        Object obj;
        try{
            obj = aClass.newInstance();
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException("创建对象失败"+e.getMessage());
        }
        // 依赖注入
        List<Property> propertyList = beanDefinition.getPropertyList();
        for(Property property : propertyList){
            String name = property.getName();
            String value = property.getValue();
            String ref = property.getRef();

            //属性值不为空才进行注入
            if(null != name && "" != name){

                //判断是基本数据类型 还是 引用类型
                if(null != value && "" != name.trim()){
                    Map<String,String> params = new HashMap<String,String>();
                    params.put(name,value);
                    try{
                        BeanUtils.populate(obj,params);
                    }catch (Exception e){
                        e.printStackTrace();
                        throw new RuntimeException("调用目标对象失败"+e.getMessage());
                    }
                }
                if(null != ref && "" != ref.trim()){
                    Map<String,Object> params = new HashMap<String,Object>();
                    try{
                        BeanUtils.setProperty(obj,name,getBean(ref));
                    }catch (Exception e){
                        e.printStackTrace();
                        throw new RuntimeException("调用目标对象失败"+e.getMessage());
                    }
                }
            }

        }

        return obj;
    }
}
